package com.ruoyi.security.service.backtest.gridtrading.strategy.impl;

import com.ruoyi.security.enums.SecurityTradeTypeEnum;
import com.ruoyi.security.service.backtest.gridtrading.strategy.RiseFallTypeCalcStrategy;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;

/**
 * 按百分比计算倍数策略
 * 
 * @author yeoman
 * @date 2025/2/4
 */
@Component("percentageMultipleStrategy")
public class PercentageMultipleStrategy implements RiseFallTypeCalcStrategy {
    
    @Override
    public int calculateMultiple(BigDecimal diff, BigDecimal benchmarkPrice, BigDecimal perRiseFallValue, String tradeType) {
        // 差值率
        BigDecimal diffRatio = diff.divide(benchmarkPrice, 4, RoundingMode.HALF_UP);
        // 涨跌幅 = 涨跌幅百分值 / 100
        BigDecimal perRiseFallValueWithoutPercent = perRiseFallValue.divide(new BigDecimal(100), 4, RoundingMode.HALF_UP);
        if (SecurityTradeTypeEnum.SELL.getKey().equals(tradeType)) {
            return (int) Math.floor(Math.log(1 + diffRatio.doubleValue()) / Math.log(1 + perRiseFallValueWithoutPercent.doubleValue()));
        }
        return (int) Math.floor(Math.log(1 - diffRatio.doubleValue()) / Math.log(1 - perRiseFallValueWithoutPercent.doubleValue()));
    }

    @Override
    public BigDecimal calculateTriggerPrice(BigDecimal benchmarkPrice, int multiple, BigDecimal perRiseFallValue, String tradeType) {
        // 涨跌幅 = 涨跌幅百分值 / 100
        BigDecimal perRiseFallValueWithoutPercent = perRiseFallValue.divide(new BigDecimal(100), 4, RoundingMode.HALF_UP);
        BigDecimal totalRiseFallValue;
        if (SecurityTradeTypeEnum.SELL.getKey().equals(tradeType)) {
            // 累计涨跌幅 = 1 + 涨跌幅
            totalRiseFallValue = new BigDecimal(1).add(perRiseFallValueWithoutPercent);
        }else {
            // 累计涨跌幅 = 1 - 涨跌幅
            totalRiseFallValue = new BigDecimal(1).subtract(perRiseFallValueWithoutPercent);
        }
        // 触发价格 = 基准价 * 累计涨跌幅倍数的次幂
        return benchmarkPrice.multiply(totalRiseFallValue.pow(multiple)).setScale(2, RoundingMode.HALF_UP);
    }

}

